using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using WeatherMcpServer.Services.Weather;
using WeatherMcpServer.Data.Entities;
using System.Globalization;

namespace WeatherMcpServer.Controllers
{
    /// <summary>
    /// 生产场景适宜性评估接口：根据天气预报给出适宜/不适宜判断、评分与建议。
    /// 默认不会改变现有逻辑，仅新增查询能力。
    /// </summary>
    [ApiController]
    [Route("api/[controller]")]
    public class ProductionController : ControllerBase
    {
        private readonly IEnumerable<IWeatherProvider> _providers;
        private readonly IConfiguration _config;

        public ProductionController(IEnumerable<IWeatherProvider> providers, IConfiguration config)
        {
            _providers = providers;
            _config = config;
        }

        /// <summary>
        /// 评估指定生产场景在目标日期的适宜性。
        /// </summary>
        /// <param name="latitude">纬度</param>
        /// <param name="longitude">经度</param>
        /// <param name="dayOffset">天偏移：0=今天，1=明天，2=后天</param>
        /// <param name="scenario">生产场景：OutdoorWork、EquipmentTempTolerance、LogisticsTransport、PersonnelSafety、InventoryManagement</param>
        /// <returns>适宜性评分、建议与触发因子</returns>
        [HttpGet("suitability")]
        public async Task<ActionResult<SuitabilityResultDto>> GetSuitability(
            [FromQuery] double latitude,
            [FromQuery] double longitude,
            [FromQuery] int dayOffset = 0,
            [FromQuery] string scenario = "OutdoorWork")
        {
            if (dayOffset < 0) dayOffset = 0; if (dayOffset > 2) dayOffset = 2;
            var merged = await GetMergedForecastAsync(latitude, longitude, dayOffset);
            if (merged == null) return Problem("No forecast available from providers.");

            var s = ParseScenario(scenario);
            var eval = EvaluateScenario(merged, s);

            var dto = new SuitabilityResultDto
            {
                Scenario = s.ToString(),
                Score = eval.Score,
                IsSuitable = eval.IsSuitable,
                Level = eval.Level,
                Reasons = eval.Reasons,
                Precautions = eval.Precautions,
                Context = new ContextDto
                {
                    TemperatureMax = merged.TemperatureMax,
                    TemperatureMin = merged.TemperatureMin,
                    RainMm = merged.RainMm,
                    WindLevel = merged.WindLevel,
                    Types = merged.Types?.Select(t => t.ToString()).ToArray() ?? Array.Empty<string>()
                }
            };
            return Ok(dto);
        }

        private enum ProductionScenario
        {
            OutdoorWork,
            EquipmentTempTolerance,
            LogisticsTransport,
            PersonnelSafety,
            InventoryManagement
        }

        private static ProductionScenario ParseScenario(string s)
        {
            return Enum.TryParse<ProductionScenario>(s, true, out var v) ? v : ProductionScenario.OutdoorWork;
        }

        private async Task<ProviderForecast?> GetMergedForecastAsync(double latitude, double longitude, int dayOffset)
        {
            var useFusion = _config.GetValue<bool>("Weather:FusionEnabled");
            var results = new List<ProviderForecast>();
            foreach (var p in _providers)
            {
                try
                {
                    var r = await p.GetForecastAsync(latitude, longitude, dayOffset);
                    if (r != null) results.Add(r);
                }
                catch { }
            }
            if (results.Count == 0) return null;
            var primary = results[0];
            if (!useFusion || results.Count == 1) return primary;
            double? max(double? a, double? b) => (a, b) switch { (null, null) => null, (double x, null) => x, (null, double y) => y, (double x, double y) => Math.Max(x, y) };
            double? min(double? a, double? b) => (a, b) switch { (null, null) => null, (double x, null) => x, (null, double y) => y, (double x, double y) => Math.Min(x, y) };
            var tMax = primary.TemperatureMax;
            var tMin = primary.TemperatureMin;
            var rain = primary.RainMm;
            var wind = primary.WindLevel;
            var types = new HashSet<WeatherType>(primary.Types ?? new List<WeatherType>());
            foreach (var r in results.Skip(1))
            {
                tMax = max(tMax, r.TemperatureMax);
                tMin = min(tMin, r.TemperatureMin);
                rain = max(rain, r.RainMm);
                wind = max(wind, r.WindLevel);
                if (r.Types != null) foreach (var t in r.Types) types.Add(t);
            }
            return new ProviderForecast(
                RegionCode: primary.RegionCode,
                RegionName: primary.RegionName,
                TemperatureMax: tMax,
                TemperatureMin: tMin,
                RainMm: rain,
                WindLevel: wind,
                Types: types.ToList()
            );
        }

        private (int Score, bool IsSuitable, string Level, List<string> Reasons, List<string> Precautions) EvaluateScenario(ProviderForecast f, ProductionScenario scenario)
        {
            // 通用指标
            var tmax = f.TemperatureMax;
            var tmin = f.TemperatureMin;
            var rain = f.RainMm ?? 0;
            var wind = f.WindLevel ?? 0;
            var hasHeavyRain = (f.Types?.Contains(WeatherType.HeavyRain) ?? false) || rain >= 25;
            var hasFog = f.Types?.Contains(WeatherType.Fog) ?? false;
            var hasStorm = f.Types?.Contains(WeatherType.Storm) ?? false;
            var hasSnow = f.Types?.Contains(WeatherType.Snow) ?? false;

            var reasons = new List<string>();
            var precautions = new List<string>();
            int score = 100;

            void Penalize(int p, string reason, string precaution)
            {
                score = Math.Max(0, score - p);
                if (!string.IsNullOrWhiteSpace(reason)) reasons.Add(reason);
                if (!string.IsNullOrWhiteSpace(precaution)) precautions.Add(precaution);
            }

            switch (scenario)
            {
                case ProductionScenario.OutdoorWork:
                    if (hasHeavyRain) Penalize(35, "强降雨", "停止高处与露天电作业，做好排水与防滑");
                    if (wind >= 6) Penalize(30, "大风(≥6级)", "停止吊装等高风险作业，固定临建");
                    if (hasStorm) Penalize(25, "雷暴/强对流", "暂停户外作业，避雷避风");
                    if (tmax.HasValue && tmax.Value >= 35) Penalize(20, "高温≥35℃", "错峰作业，补给防暑");
                    if (tmin.HasValue && tmin.Value <= -5) Penalize(20, "严寒≤-5℃", "增配保暖与防滑");
                    break;
                case ProductionScenario.EquipmentTempTolerance:
                    if (tmax.HasValue && tmax.Value >= 40) Penalize(40, "环境温度>40℃", "降温/停机保护，加强通风散热");
                    if (tmin.HasValue && tmin.Value <= -10) Penalize(35, "环境温度<-10℃", "预热启机，防护低温脆裂");
                    if (hasHeavyRain) Penalize(20, "强降雨湿度高", "防潮防水，检查配电箱密封");
                    break;
                case ProductionScenario.LogisticsTransport:
                    if (hasFog) Penalize(25, "雾", "限速、开启雾灯、必要时停运");
                    if (hasSnow) Penalize(30, "雪/结冰风险", "防滑链、非必要不出车");
                    if (rain >= 50) Penalize(30, "暴雨", "规划绕行，避免积水路段");
                    if (wind >= 8) Penalize(30, "大风(≥8级)", "高货厢禁行，检查捆扎");
                    break;
                case ProductionScenario.PersonnelSafety:
                    if (hasStorm) Penalize(35, "雷暴", "室内避险，中止室外会议/集会");
                    if (tmax.HasValue && tmax.Value >= 37) Penalize(30, "酷热≥37℃", "缩短暴露时间，补盐补水");
                    if (tmin.HasValue && tmin.Value <= -10) Penalize(30, "严寒≤-10℃", "防冻伤，暖棚休息");
                    if (wind >= 7) Penalize(20, "大风(≥7级)", "戴防护眼镜与安全帽束紧");
                    break;
                case ProductionScenario.InventoryManagement:
                    if (tmax.HasValue && tmax.Value >= 32) Penalize(20, "高温影响易腐品", "冷链加强、缩短常温停留");
                    if (tmin.HasValue && tmin.Value <= 0) Penalize(15, "低温影响液体与化学品", "保温与加热垫处理");
                    if (rain >= 25) Penalize(25, "强降雨渗漏风险", "库房防潮、防水布覆盖");
                    break;
            }

            // 汇总
            string level = score >= 80 ? "适宜" : score >= 60 ? "可控" : "不适宜";
            bool isSuitable = score >= 80;
            return (score, isSuitable, level, reasons, precautions);
        }

        // 输出模型
        public sealed class SuitabilityResultDto
        {
            /// <summary>生产场景</summary>
            public string Scenario { get; set; } = string.Empty;
            /// <summary>0-100 评分</summary>
            public int Score { get; set; }
            /// <summary>是否适宜（Score≥80）</summary>
            public bool IsSuitable { get; set; }
            /// <summary>等级：适宜/可控/不适宜</summary>
            public string Level { get; set; } = string.Empty;
            /// <summary>触发的影响因子</summary>
            public List<string> Reasons { get; set; } = new();
            /// <summary>建议与预防措施</summary>
            public List<string> Precautions { get; set; } = new();
            /// <summary>用于前端展示的上下文</summary>
            public ContextDto Context { get; set; } = new();
        }

        public sealed class ContextDto
        {
            public double? TemperatureMax { get; set; }
            public double? TemperatureMin { get; set; }
            public double? RainMm { get; set; }
            public double? WindLevel { get; set; }
            public string[] Types { get; set; } = Array.Empty<string>();
        }
    }
}
